/******************************************************************************
 * Author:      671643387
 * Created:     2016/10/26
 *****************************************************************************/

var util            = require("util");
var Enum            = require("./Enum.js");
var Player          = require("./Player.js").Player;
var ProtoID         = require("../../../net/ProtoID.js").ProtoID;
var ProtoState      = require("../../../net/ProtoID.js").ProtoState;
var Opcodes         = require("./Opcodes.js").Opcodes;
var mUtil           = require("./util.js");


///////////////////////////////////////////////////////////////////////////////
//>> 公牌

function HandCards() {
    this.num        = 0;    // 剩余牌数量
    this.cards      = [];   // 牌

    this.getIndex   = 0;    // 取牌位置
}

HandCards.prototype = {

    // 生成牌组
    gen: function(roomType, selectIsWind) {
        // 初始化数据
        this.cards = mUtil.genMahjong("qinghaijimi", roomType, selectIsWind);
        this.num = this.cards.length;
        this.getIndex = 0;
    },

    testGan:function(roomType, selectIsWind) {
        // 初始化数据
        this.cards = mUtil.tesetMahjong("qinghaijimi", roomType, selectIsWind);
        this.num = this.cards.length;
        this.getIndex = 0;
    },

    // 摸牌
    getCards: function(num) {
        var rtnCards = [];
        this.num -= num;
        while (num > 0) {
            rtnCards.push(this.cards[this.getIndex]);
            ++this.getIndex;
            num -= 1;
        }
        return rtnCards;
    },

    // 获取剩余牌数量
    getRemain: function() {
        return this.num;
    },
};

///////////////////////////////////////////////////////////////////////////////
//>> 游戏房间

function Room(id) {
    this.creator        = 0;        // 房主
    this.id             = id;       // 房间号
    this.totalRound     = 0;        // 总轮数
    this.roomType       = 0;        // 当前房间游戏类型
    this.roomIntegral      = 0;        // 当前房间游戏底分
    this.selectWind     = 0;        // 当前房间是否有风
    this.selectIsEat    = 0;        // 当前房间是否能吃

    this.players        = {};
    this.joinedPlayers  = 0;        // 已经加入房间的人数
    this.readyPlayers   = 0;        // 准备就绪的玩家
    this.onlinePlayers  = 0;        // 在线玩家数量

    this.isReqDestroy   = false;    // 是否申请解散
    this.destroyTime    = 0;        // 销毁时间
    this.respDestroyOKs = {};       // 同意解散房间的人
    this.destroyTimer   = null;     // 解散计时器
    this.repDestroyPlayerIdx = 0;        // 解散时玩家数量

    // 游戏数据
    this.mahjongs       = null;       // 底牌
    this.curRound       = 0;        // 当前轮
    this.dealer         = 0;        // 庄家
    this.curPlay        = 0;        // 当前出牌的人
    this.isHupai        = false;    // 房间是否有人胡牌

    this.mixCard        = 0;        // 带混规则用到的混牌

    this.hasSendCards   = false;    // 是否已经发牌
    this.hangupStart    = false;    // 挂起的开始游戏
    this.isSendSett     = false;    // 是否发送结算
    this.canHuNum       = 0;        // 能胡牌玩家的数量
    this.canPengGanNum  = 0;        // 能碰杠牌玩家的数量
    this.canChiNum      = 0;        // 能吃牌玩家的数量

    this.dianPaoUid     = 0;        // 点炮玩家UID
    this.huPlayers      = [];       // 胡牌玩家数组
    this.takeCardIdx    = 0;        // 当前摸牌Index

    ///////////////////// save playback date
    this.roomPlayInfoPage = {};
    this.playBackPage   = [];
    this.playBackDates   = [];
    ///////////////////////////////////////
}

Room.prototype = {

    // 初始化
    init: function(creator, cArgs) {
        var totalRound = +cArgs.totalRound;
        var roomType = +cArgs.roomType;
        var roomIntegral = +cArgs.roomIntegral;

        //带混（默认带风、不能吃）
        var selectWind = true;
        var selectIsEat = false;

        // 258做将（可选带风，可选吃）
        if(roomType == 2){selectIsEat = cArgs.selectIsEat;}
        if(roomType == 2){selectWind = cArgs.selectWind;}

        // 初始化房间全局数据
        this.creator = creator;
        this.totalRound = totalRound;
        this.roomType = roomType;
        this.roomIntegral = roomIntegral;
        this.selectWind = selectWind;
        this.selectIsEat = selectIsEat;

        // 初始化房间玩家数据
        for (var iPlayer = 1; iPlayer <= 4; ++iPlayer) {
            this.players[iPlayer] = new Player(this, iPlayer);
        }

        this.mahjongs = new HandCards();
        this.dealer = 0;
        this.roomPlayInfoPage = {};
        this.playBackPage = [];
        this.playBackDates = [];
        return true;
    },

    // 获取房间号
    getId: function() {
        return this.id;
    },

    // 枚举玩家
    enumPlayers: function(enumtor) {
        for (var playerIdx in this.players) {
            if (!this.players.hasOwnProperty(playerIdx)) {
                continue;
            }
            if (enumtor(+playerIdx, this.players[playerIdx]) === false) {
                break;
            }
        }
    },
    getPlayerHandles: function (uid) {
        var playerHandles = null;
        if(this.players){
            for(var key in this.players){
                if(!this.players.hasOwnProperty(key)){
                    continue;
                }
                var temp = this.players[key];
                if(temp && temp.uid == uid){
                    playerHandles = temp;
                    break;
                }
            }
        }
        return playerHandles;
    },

    getPlayerIdx: function ( uid ) {
        var playerIdx = 0;
        if(this.players){
            for(var key in this.players){
                if(!this.players.hasOwnProperty(key)){
                    continue;
                }
                var temp = this.players[key];
                if(temp && temp.uid == uid){
                    playerIdx = +key;
                    break;
                }
            }
        }
        return playerIdx;
    },
    // 广播消息
    broadcastMsg: function(code, args, excludes) {
        excludes = excludes || [];
        this.enumPlayers(function(ePlayerIdx, ePlayer){
            if ((excludes.indexOf(ePlayerIdx) == -1) && ePlayer.isInited()) {
                ePlayer.sendMsg(code, args);
            }
        });
        /*///////////////////// save playback date
        if(Opcodes.SMSG_SET_PLAYER_TAKE_CARD != code) {
            this.playBackPage.push({
                code: code, args: args
            });
        }
        ////////////////////////////////////////*/
    },

    modifyOnlinePlayers: function(val) {
        this.onlinePlayers += val;
        Assert((this.onlinePlayers >= 0 && this.onlinePlayers <= 4)
            , "修改在线玩家出错, onlinePlayers=" + this.onlinePlayers);
    },


    // 添加一个玩家
    addPlayer: function(jArgs, wsConn) {
        var playerIndex = this.getPlayerIndex(jArgs.uid);
        if (playerIndex != 0) {
            var player = this.getPlayerHandles(+jArgs.uid);

            // 不在线，  房间内人数加一
            if(!player.online) {
                this.modifyOnlinePlayers(1);
            }

            if (player.wsConn) {
                player.wsConn.close();
                player.wsConn = null;
            }

            player.setNewConn(wsConn);

            player.onPlayerResped();
            this.onPlayerReconnect(playerIndex, wsConn);

            // 重连进来准备并且没有之前没有发牌，有给玩家自己准备
            if(!player.getReady() && !this.hasSendCards){
                this.onPlayerInRoomReady(player.uid);
            }
            return 0;
        }

        // 检查房间是否已满
        if (this.joinedPlayers == Enum.ROOM_PLAYER_NUM) {
            return ProtoState.STATE_ROOM_FULL;
        }

        for (var iK in this.players) {
            if (!this.players[iK].isInited()) {
                playerIndex = +iK;
                break;
            }
        }

        var player = this.players[playerIndex];
        player.init(jArgs, wsConn);
        this.joinedPlayers += 1;
        this.modifyOnlinePlayers(1);

        // 广播消息
        this.broadcastMsg(ProtoID.SMSG_PLAYER_JOIN_ROOM, {
            playerIndex : playerIndex,
            player      : player.getInfo(),
        }, [playerIndex]);

        // 准备返回给玩家的初始化数据
        var initArgs = {
            curRound    : this.curRound,
            totalRound  : this.totalRound,
            roomType    : this.roomType,
            selectWind  : this.selectWind,
            selectIsEat : this.selectIsEat,
            roomIntegral: this.roomIntegral,
            dealer      : this.dealer,
            players     : {},
            playerIndex : playerIndex,
        };
        this.enumPlayers(function(ePlayerIdx, ePlayer){
            if (ePlayer.isInited()) {
                initArgs.players[ePlayerIdx] = ePlayer.getInfo();

                /*///////////////////// save playback date
                this.roomPlayInfoPage[ePlayerIdx] = {
                    info: ePlayer.info,
                    score: ePlayer.score,
                    index: ePlayerIdx,
                };
                ////////////////////////////////////////*/
            }
        }.bind(this));

        // 给新玩家推送消息
        player.sendMsg(ProtoID.SMSG_JOIN_ROOM, initArgs);

        ///////////////////// save playback date
        //player.playBackPage.push(ProtoID.SMSG_JOIN_ROOM, initArgs);
        ////////////////////////////////////////
        return 0;
    },

    onPlayerReconnect: function(playerIndex, wsConn) {
        var myThis = this;
        var player = myThis.players[playerIndex];
        var isOperation = myThis.canChiNum || myThis.canHuNum || myThis.canPengGanNum ? true : false;
        // 发送房间数据
        var recArgs = {
            totalRound  : myThis.totalRound,    // 总轮数
            curRound    : myThis.curRound,      // 当前轮数
            curPlay     : myThis.curPlay,       // 当前出牌玩家
            roomType    : myThis.roomType,
            selectWind  : myThis.selectWind,
            selectIsEat : myThis.selectIsEat,
            roomIntegral: myThis.roomIntegral,
            dealer      : myThis.dealer,
            curMahjong  : myThis.curMahjong,    // 桌子上当前出的牌
            takeCardIdx : myThis.takeCardIdx,   // 当前拿牌人的index
            isOperation : isOperation,          // 当前是否有人可操作
            remainCards : myThis.mahjongs.getRemain(),
            mixCard     : myThis.mixCard,       // 混牌
            playerIndex : playerIndex,        // 玩家位置
            players     : {},                 // 玩家数据
        };

        // 获取玩家数据
        myThis.enumPlayers(function(ePlayerIdx, ePlayer){
            if (ePlayer.isInited()) {
                recArgs.players[ePlayerIdx] = ePlayer.getRecInfo((ePlayer.uid == player.uid));
            }
        });

        // 通知玩家上线
        myThis.broadcastMsg(Opcodes.SMSG_SET_PLAYER_ONLINE, {
            playerIndex : playerIndex,
        },[playerIndex]);

        player.sendMsg(Opcodes.SMSG_SET_PLAYER_RECONNECT, recArgs);

        setTimeout(function(){
            if(!myThis.hangupStart) {
                // 发送提示
                if(myThis.canHuNum > 0 && player.hasTip('hupai')){
                    player.sendTips();
                }else if(myThis.canPengGanNum > 0 && (player.hasTip('gangpai') || player.hasTip('pengpai'))){
                    player.sendTips();
                }else if(myThis.canHuNum == 0 && myThis.canPengGanNum == 0){
                    player.sendTips();
                }
                // 当前状态是申请解散状态，发送给玩家解散状态
                if(myThis.isReqDestroy){
                    player.sendMsg(Opcodes.SMSG_RECONNECT_CUR_DISSOLUTION, myThis.getDissolutionRoomInfo());
                }
            }else{
                // 给单个玩家推结算信息
                player.sendMsg(Opcodes.SMSG_SET_ROUND_SETTEMENT, myThis.getSettementInfo());
            }
        }, 200);

        return true;
    },
    getSettementInfo: function () {
        var myThis = this;
        // 发送结算信息
        var settementInfo = {};
        settementInfo["round"] = myThis.curRound;
        settementInfo["wind"] = myThis.selectWind;
        settementInfo["yuNum"] = myThis.roomIntegral;
        settementInfo["players"] = null;
        var playerinfo = [];
        myThis.enumPlayers(function (ePlayerIdx, ePlayer) {
            playerinfo.push(ePlayer.getSettementInfo());
        });
        settementInfo["players"] = playerinfo;
        return settementInfo;
    },
    getDissolutionRoomInfo: function () {
        var info = {};
        info["repPlayer"] = this.repDestroyPlayerIdx;
        var OkIdx = [];
        for (var key in this.respDestroyOKs){
            if(this.respDestroyOKs[key]){
                key = +key;
                if(key == 1){
                    continue;
                }
                var player = this.players[key];
                if(player){
                    OkIdx.push({index:key, name:player.info.name});
                }
            }
        }
        info["okIdx"] = OkIdx;
        return info;
    },

    // 获取玩家索引
    getPlayerIndex: function(uid) {
        for (var playerIdx in this.players) {
            if (!this.players.hasOwnProperty(playerIdx)) {
                continue;
            }

            if (this.players[playerIdx].isPlayer(uid)) {
                return +playerIdx;
            }
        }
        return 0;
    },

    // 输出房间信息
    dump: function() {
        DEBUG(util.format("Room %d created { round: %d, roomType: %d, selectIsEat: %d, selectIsWind: %d}",
            this.id, this.totalRound, this.roomType, this.selectIsEat, this.selectWind));
    },

    ///////////////////////////////////////////////////////////////////////////

    // 玩家消息
    onPlayerMsg: function(player, msg) {
        DEBUG(util.format("onPlayerMsg -> %d, %j", player.uid, msg));

        switch (msg.code) {
            case Player.MSG_PENG_CARD:
                break;
            case Player.MSG_CHI_CARD:
                break;
            // 自摸胡牌消息
            case Player.MSG_HU_CARD:
                break;
            // 玩家离线
            case Player.MSG_PLAYER_OFFLINE:
                this.onPlayerOffline(player);
                break;
        }
    },

    onPlayerOffline: function(player) {
        var playerIndex = this.getPlayerIndex(player.uid);
        DEBUG(util.format("Player %d is offline", player.uid));
        this.modifyOnlinePlayers(-1);

        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_OFFLINE, {
            playerIndex     : playerIndex,
        }, [playerIndex]);
    },

    // 房间开始新一轮游戏
    onRoomStartNewRound: function() {
        var myThis = this;
        if (myThis.curRound >= myThis.totalRound) {
            // 游戏结束
            Assert(false, "Not reach here");
            return;
        }

        // 初始化游戏数据
        myThis.mahjongs.gen(myThis.roomType, myThis.selectWind);
        //myThis.mahjongs.testGan(myThis.roomType, myThis.selectWind);
        myThis.curRound += 1;

        myThis.curPlay = myThis.dealer; // 设置出牌玩家为庄家
        myThis.hangupStart = false;
        myThis.isSendSett = false;
        myThis.mixCard = 0;

        // 清除胡牌信息
        myThis.isHupai = false;
        myThis.canHuNum = 0;
        myThis.canPengGanNum = 0;
        myThis.canChiNum = 0;
        myThis.takeCardIdx = 0;
        myThis.huPlayers = [];

       /* ///////////////////// save playback date
        this.playBackPage = [];
        ////////////////////////////////////////
*/
        // 广播房间状态
        myThis.broadcastMsg(ProtoID.SMSG_SET_ROOM_INFO, {
            curRound:   myThis.curRound,
            dealer:     myThis.dealer,
        });

        // 尾部倒数七张抽取为混牌
        if(1 == myThis.roomType) {
            myThis.randomTakeMixCard();
        }
        // 给玩家发牌
        myThis.enumPlayers(function(ePlayerIndex, ePlayer){

            ePlayer.setHandCards(myThis.mahjongs.getCards(Enum.PLAYERHANDLECARDNUM));

            /*///////////////////// save playback date
            var handCards = ePlayer.handsCards.gethandEffectiveCards();
            var dateCards = clone(handCards);
            myThis.playBackPage.push({
                code: Opcodes.SMSG_SET_PLAYER_CARDS,
                args: {
                    cards: dateCards,
                    index: ePlayerIndex,
                }
            });
            ////////////////////////////////////////*/

            if(1 == myThis.roomType) {
                ePlayer.setMixCard(myThis.mixCard);
            }
        });

        myThis.onSetPlayersHandCards();
    },

    // 开局给玩家发完手牌后逻辑
    onSetPlayersHandCards: function() {
        var myThis = this;

        if(1 == myThis.roomType) {
            // 发送混牌消息
            myThis.broadcastMsg(Opcodes.SMSG_SET_ROOM_MIX_CARD, {
                mixCard: myThis.mixCard,
            });
        }

        // 设置当前出牌玩家
        myThis.sendPlayCardPlayer(this.curPlay, true);

    },

    // 定混牌
    randomTakeMixCard: function () {
        var myThis = this;
        if(myThis.mahjongs.getRemain()>0){
            var pos = (myThis.mahjongs.getRemain() - 7) - 1;
            var temp = myThis.mahjongs.cards[pos];
            myThis.mixCard = (temp.type - 1) * 9 + temp.value;
            LOG(util.format("Room: %d， mixCard: %d, pos: %d", myThis.id, myThis.mixCard, pos));
        }
    },

    // 发牌并通知客户端该谁出牌
    sendPlayCardPlayer: function(pos, dealCard) {

        var myThis = this;
        if (dealCard && this.mahjongs.getRemain() == 0) {
            //当前局结束
            myThis.onSettement(true);
            return;
        }

        pos = pos || (this.curPlay + 1);
        myThis.curPlay = pos;
        if (myThis.curPlay > myThis.joinedPlayers) {
            myThis.curPlay = 1;
        }

        myThis.broadcastMsg(Opcodes.SMSG_SET_PLAY_CARD_PLAYER, {
            curPlay: myThis.curPlay
        });

        if (dealCard) {
            myThis.takeCardIdx = myThis.curPlay;
            var curPlayer = myThis.players[myThis.curPlay];

            var card = myThis.mahjongs.getCards(1)[0];
            /*///////////////////// save playback date
            var newMahjong = (card.type - 1) * 9 + card.value;
            myThis.playBackPage.push({
                code: Opcodes.SMSG_SET_PLAYER_HAND_CARD,
                args: {
                    cards: newMahjong,
                    mixCard: myThis.mixCard,
                    index: myThis.curPlay,
                }
            });
            /////////////////////////////////////////*/
            curPlayer.setNewMahjong(card);

            if (curPlayer.hasTip('hu')) {
                myThis.canHuNum += 1;
            }
            myThis.broadcastMsg(Opcodes.SMSG_SET_PLAYER_TAKE_CARD, {
                curPlay: myThis.curPlay,
            },[myThis.curPlay]);

            myThis.broadcastMsg(Opcodes.SMSG_REMAIN_CARD_NUM, {
                remainCards: myThis.mahjongs.getRemain(),
            });
        }
    },

    // 立即销毁房间
    destroyRoomImmd: function() {
        // 房间结束
        DEBUG("==== GAME shutdown ");
        var myThis = this;
        myThis.broadcastMsg(Opcodes.SMSG_SET_ROOM_FINISHED, {});


        // 销毁房间
        DEBUG(util.format("==== Destroy Room %d", myThis.id));
        myThis.onRoomDestroy();

        // 减少房间用量
        GameMgr.decUsage();

        GameMgr.getSubGame().destroyRoom(this);
    },

    onRoomDestroy: function() {
        var uids = [];
        this.enumPlayers(function (eNotUse, ePlayer) {
            if (ePlayer.isInited()) {
                uids.push(ePlayer.uid);
                ePlayer.destroy();
            }
        });

        this.players =[];
        this.roomPlayInfoPage = {};
        this.playBackPage = [];
        this.playBackDates = [];

        GameMgr.sendMgrMsg({
            code    : ProtoID.SMSG_REQ_DESTROY_ROOM,
            args    : {
                uids        : uids,
            },
        });
    },

    shutdown: function() {
        DEBUG(util.format("Shutdown room %d", this.id));

        if ((this.curRound > 1) || this.isHupai) {
            this.curRound = this.totalRound;
            this.onSettement(false);
        } else {
            this.destroyRoomImmd();
        }
    },

    ///////////////////////////////////////////////////////////////////////////

    onPlayerReqPlayCard: function(uid, card) {
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex != this.curPlay) {
            ERROR(util.format("Not player %d's round"));
            return;
        }
        if (1 > playerIndex || playerIndex > this.joinedPlayers) {
            ERROR(util.format("PLAY:    Not player %d's index erorr"));
            return;
        }
        if(card == this.mixCard){
            ERROR(util.format("PLAY:    Not Play mixCard: %d",card));
            return;
        }
        if(this.canHuNum > 0 || this.canPengGanNum > 0 || this.canChiNum > 0){
            ERROR(util.format("PLAY:    Play have operation"));
            return;
        }
        var player = this.players[playerIndex];

        player.onPlayerResped();
        if (!player.playCard(card)) {
            ERROR(util.format("Player %d's play Card error"));
            return;
        }

        this.curMahjong = card;
        player.playedCards.push(card);

        this.playCard(playerIndex, player, card);
        return 0;
    },

    playCard: function(playerIndex, player, card) {
        var myThis = this;
        // 出牌
        myThis.broadcastMsg(Opcodes.SMSG_SET_PLAYED_CARD, {
            playerIndex: playerIndex,
            card: card,
        });

        ///////////////////////////////////////////////////////////////////////
        // 检查其他玩家
        myThis.canHuNum = 0;
        myThis.canPengGanNum = 0;
        myThis.canChiNum = 0;
        var canPlayerDoAction = false;
        myThis.enumPlayers(function (ePlayerIndex, ePlayer) {
            if (ePlayerIndex != playerIndex) {
                if (ePlayer.isHu()) {
                    return;
                }
                if(ePlayer.checkWithPlayedPubCard(card)){
                    canPlayerDoAction = true;
                }
                canPlayerDoAction = canPlayerDoAction || ePlayer.hasAnyTip();
                if (ePlayer.hasTip('hu')) {
                    myThis.canHuNum += 1;
                    //LOG(util.format("check HuPai %d",myThis.canHuNum));
                }
                if(ePlayer.hasTip('peng') || ePlayer.hasTip('gang')){
                    myThis.canPengGanNum += 1;
                    //LOG(util.format("check canPengGanNum %d",myThis.canHuNum));
                }
                if(ePlayer.hasTip('chi')){
                    myThis.canChiNum += 1;
                    //LOG(util.format("check canPengGanNum %d",myThis.canHuNum));
                }
            }
        });

        if (canPlayerDoAction) {
            // 其他玩家可以碰牌或者杠牌
            if (myThis.canHuNum > 0) {
                //LOG(util.format("check Player Operation HuPai %d",myThis.canHuNum));
                // 给可以胡牌的玩家发提示
                myThis.enumPlayers(function(ePlayerIdx, ePlayer){
                    if (ePlayerIdx == playerIndex || ePlayer.isHu()) {
                        return;
                    }
                    if (ePlayer.hasTip('hu')) {
                        ePlayer.sendTips(myThis.canHuNum != 1);
                    }
                });
            } else if(myThis.canPengGanNum > 0){
                // 给可以杠牌或者碰牌发提示
                //LOG(util.format("check Player Operation PengGang %d", myThis.canPengGanNum));
                myThis.enumPlayers(function(ePlayerIdx, ePlayer){
                    if (ePlayerIdx == playerIndex || ePlayer.isHu()) {
                        return;
                    }
                    if(ePlayer.hasTip('gang') || ePlayer.hasTip('peng')) {
                        ePlayer.sendTips();
                    }
                });
            }else {
                // 给可以吃牌的玩家发提示
                //LOG(util.format("check Player Operation chi"));
                myThis.enumPlayers(function(ePlayerIdx, ePlayer){
                    if (ePlayerIdx == playerIndex || ePlayer.isHu()) {
                        return;
                    }
                    ePlayer.sendTips();
                });
            }
        } else {
            // 其他玩家啥都不能干
            LOG(util.format("check Player Not Operation"));
            myThis.sendPlayCardPlayer(0, true);
        }
        return 0;
    },


    onPlayerReqPengCard: function(uid) {
        // 检查玩家能否碰牌
        var playerIndex = this.getPlayerIndex(uid);
        if (1 > playerIndex || playerIndex > this.joinedPlayers) {
            ERROR(util.format("PENG:    Not player %d's index erorr"));
            return;
        }
        var player = this.players[playerIndex];
        // 胡减一
        if(player.hasTip('hu')){
            this.canHuNum -= 1;
        }
        this.canChiNum = 0;
        // 碰杠减一
        this.canPengGanNum -= 1;

        player.onPlayerResped();
        var val = player.pengCard(this.curPlay);
        if (-1 == val) {
            ERROR(util.format("Player %d's Peng Card error"));
            return;
        }

        // 当前牌有人操作，从出牌人手中扣出当前牌
        var ovrPlayer = this.players[this.curPlay];
        ovrPlayer.playedCards.splice(ovrPlayer.playedCards.length - 1, 1);

        /*///////////////////// save playback date
         this.playBackPage.push({
             code: Opcodes.CMSG_PLAYER_PENG_CARD,
             args: {
                 index: playerIndex,
                 Operation: "pengpai",
             },
         });
        ////////////////////////////////////////*/


        this.curMahjong = 0;
        this.takeCardIdx = 0;

        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_PENG_CARD,{
            card: val,
            playerIndex: playerIndex
        });

        this.sendPlayCardPlayer(playerIndex, false);
    },

    onPlayerReqChiCard:function (uid, cards) {
        // 检查玩家能否吃牌
        var playerIndex = this.getPlayerIndex(uid);
        if (1 > playerIndex || playerIndex > this.joinedPlayers) {
            ERROR(util.format("CHI:     Not player %d's index erorr"));
            return;
        }
        var player = this.players[playerIndex];

        // 胡减一
        if(player.hasTip('hu')){
            this.canHuNum -= 1;
        }
        // 碰杠减一
        if(player.hasTip('peng') || player.hasTip('gang')){
            this.canPengGanNum -= 1;
        }

        this.canChiNum -= 1;

        player.onPlayerResped();
        var val = player.chiCard(this.curMahjong, cards, this.curPlay);
        if (-1 == val) {
            ERROR(util.format("Player %d's chi Card error"));
            return;
        }
        // 当前牌有人操作，从出牌人手中扣出当前牌
        var ovrPlayer = this.players[this.curPlay];
        ovrPlayer.playedCards.splice(ovrPlayer.playedCards.length - 1, 1);

        /*///////////////////// save playback date
        this.playBackPage.push({
            code: Opcodes.CMSG_PLAYER_CHI_CARD,
            args: {
                index: playerIndex,
                Operation: "chi",
            },

        });
        ////////////////////////////////////////*/

        this.curMahjong = 0;
        this.takeCardIdx = 0;
        var listChiInfo = [];
        listChiInfo.push(cards);
        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_CHI_CARD,{
            card:val,
            cards: listChiInfo,
            playerIndex: playerIndex,
        });

        this.sendPlayCardPlayer(playerIndex, false);
    },

    onPlayerReqGangCard: function(uid) {
        // 检查玩家能否碰牌
        var playerIndex = this.getPlayerIndex(uid);
        if (1 > playerIndex || playerIndex > this.joinedPlayers) {
            ERROR(util.format("PANG:    Not player %d's index erorr"));
            return;
        }
        var player = this.players[playerIndex];

        // 胡减一
        if(player.hasTip('hu')){
            this.canHuNum -= 1;
        }

        this.canChiNum = 0;

        // 碰杠减一
        this.canPengGanNum -= 1;

        player.onPlayerResped();
        var val = player.gangCard(this.curPlay,playerIndex);
        if (!val) {
            ERROR(util.format("Player %d's gang Card error"));
            return;
        }
        if(val.backBeltMark == Enum.PlayerMark.PLAYER_TIP_MG){
            var coverPengPlayer = this.players[this.curPlay];

            if( this.curMahjong != 0) {
                //被点杠
                coverPengPlayer.handsCards.addGang(this.curMahjong, Enum.PlayerMark.PLAYER_TIP_BG, playerIndex);

                // 当前牌有人操作，从出牌人手中扣出当前牌
                coverPengPlayer.playedCards.splice(coverPengPlayer.playedCards.length - 1, 1);
            }
        }

        this.curMahjong = 0;
        this.takeCardIdx = 0;

        /*///////////////////// save playback date
        this.playBackPage.push({
            code: Opcodes.CMSG_PLAYER_PENG_CARD,
            args: {
                index: playerIndex,
                Operation: "gangpai",
            },
        });
        ////////////////////////////////////////*/

        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_GANG_CARD,val);

        this.sendPlayCardPlayer(playerIndex, true);
    },

    onPlayerReqHuCard: function(uid) {
        var playerIndex = this.getPlayerIndex(uid);
        if (1 > playerIndex || playerIndex > this.joinedPlayers) {
            ERROR(util.format("HUCARD:    Not player %d's index erorr"));
            return;
        }
        var curPlayer = this.players[playerIndex];

        curPlayer.onPlayerResped();

        // 检查玩家能否胡牌
        if(!curPlayer.myHuCard()){
            ERROR(util.format("HUCARD:  Player Not huPai: error"));
            return;
        }

        this.huPlayers.push(uid);
        this.isHupai = true;
        this.canHuNum -= 1;
        this.dealer = playerIndex;
        this.takeCardIdx = 0;

        // 当前胡牌玩家是接炮
        if(curPlayer.hasHuPaiMethod(Enum.HupaiMethod.METHOD_DIANPAO_PAIRS)) {
            var coverHuPaiPlayer = this.players[this.curPlay];
            // 当前牌有人操作，从出牌人手中扣出当前牌
            coverHuPaiPlayer.playedCards.splice(coverHuPaiPlayer.playedCards.length - 1, 1);

            // 设置点炮玩家
            if (!coverHuPaiPlayer.isHu()) {
                this.dianPaoUid = coverHuPaiPlayer.uid;
            }
            // 点炮，给当时出牌玩家加点炮
            coverHuPaiPlayer.pushHuPaiMethod(Enum.HupaiMethod.METHOD_COVER_DIANPAO);
            coverHuPaiPlayer.dianPaoNum += 1;
        }
        /*///////////////////// save playback date
        this.playBackPage.push({
            code: Opcodes.CMSG_PLAYER_PENG_CARD,
            args: {
                index: playerIndex,
                Operation: "hupai",
            },
        });
        ////////////////////////////////////////*/

        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_HU_CARD,{
            playerIndex: playerIndex,
            huType: curPlayer.getHuPaiMethod(),
            card:curPlayer.huCard,
        });

        LOG(util.format("HUCARD HuPai %d",this.canHuNum));

        if (this.canHuNum == 0) {
            // 能糊的人都糊了
            this.curMahjong = 0;
            if (0) {
                // 有人胡牌后游戏还能继续
                // TODO
            } else {
                // 有人胡牌后游戏不能继续,计算当前局
                this.onSettement(true);
            }
        } else {
            // 等待其他可以胡牌的玩家胡牌或者跳过
        }

        curPlayer.clearTips();
    },

    onPlayerReqPass: function(uid) {
        var myThis = this;
        var playerIndex = myThis.getPlayerIndex(uid);
        if (1 > playerIndex || playerIndex > myThis.joinedPlayers) {
            ERROR(util.format("PASS:    Not player %d's index erorr"));
            return;
        }
        var player = myThis.players[playerIndex];

        /*///////////////////// save playback date
        this.playBackPage.push({
            code: Opcodes.CMSG_PLAYER_PENG_CARD,
            args: {
                index: playerIndex,
                Operation: "pass",
            },
        });
        ////////////////////////////////////////*/

        // 胡减一
        if(player.hasTip('hu')){
            myThis.canHuNum -= 1;
        }
        // 碰杠减一
        if(player.hasTip('peng') || player.hasTip('gang')){
            myThis.canPengGanNum -= 1;
        }
        if(player.hasTip('chi')){
            this.canChiNum -= 1;
        }
        player.onPlayerResped();
        if(playerIndex == myThis.curPlay){
            // 该当前玩家出牌，自己的杠没有杠， 不判断后面的逻辑，不能让过，正常逻辑
            player.clearTips();
            return;
        }

        // 先pass 胡牌，  后pass 碰杠，再pass 吃操作
        if (player.hasTip('hu')) {
            player.clearTips();
            player.isErrorHu = true;
            LOG(util.format("onPlayerReqPass Player Pass HuPai %d",myThis.canHuNum));
            if (myThis.canHuNum == 0) {
                if (myThis.isHupai) {
                    // 房间有人和牌且游戏不能继续，结算当前局
                    myThis.onSettement(true);
                } else {
                    // 继续游戏
                    var doAnyAction = false;    // 是否给其他玩家发送提示,如果有发送等待其他玩家操作
                    myThis.enumPlayers(function (playerIndex, ePlayer) {
                        if (ePlayer.isPlayer(uid) || ePlayer.isHu()) {
                            return;
                        }
                        if (ePlayer.hasAnyTip()) {
                            if(ePlayer.hasTip('chi') && myThis.canPengGanNum > 0){
                                return;
                            }
                            ePlayer.sendTips();
                            doAnyAction = true;
                        }
                    });
                    if (!doAnyAction) {
                        // 之前出的牌没有人操作 ，加入已出过牌中
                        var playPlayer = myThis.players[myThis.curPlay];
                        playPlayer.playedCards.push(myThis.curMahjong);

                        // 没有给其他玩家发送提示
                        myThis.sendPlayCardPlayer(0, true);
                    }
                }
            }
        }else if(player.hasTip('gang') || player.hasTip('peng')){
            player.clearTips();
            LOG(util.format("onPlayerReqPass Player Pass gangpeng %d",myThis.canHuNum));
            if(myThis.canPengGanNum > 1){
                var doAnyAction = false;    // 是否给其他玩家发送提示,如果有发送等待其他玩家操作
                myThis.enumPlayers(function (playerIndex, ePlayer) {
                    if (ePlayer.isPlayer(uid) || ePlayer.isHu()) {
                        return;
                    }
                    if (ePlayer.hasAnyTip()) {
                        if(ePlayer.hasTip('chi') && myThis.canPengGanNum > 0){
                            return;
                        }
                        ePlayer.sendTips();
                        doAnyAction = true;
                    }
                });
                LOG(util.format("onPlayerReqPass Player GangPeng %d, flag %d",myThis.canHuNum,doAnyAction));
                if (!doAnyAction) {
                    // 之前出的牌没有人操作 ，加入已出过牌中
                    var playPlayer = myThis.players[myThis.curPlay];
                    playPlayer.playedCards.push(myThis.curMahjong);

                    // 没有给其他玩家发送提示
                    myThis.sendPlayCardPlayer(0, true);
                }
            }else{
                LOG(util.format("onPlayerReqPass Player chi %d",myThis.canHuNum));
                myThis.enumPlayers(function (playerIndex, ePlayer) {
                    if (ePlayer.isPlayer(uid) || ePlayer.isHu()) {
                        return;
                    }
                    if (ePlayer.hasAnyTip()) {
                        ePlayer.sendTips();
                        doAnyAction = true;
                    }
                });
                if (!doAnyAction) {
                    // 之前出的牌没有人操作 ，加入已出过牌中
                    var playPlayer = myThis.players[myThis.curPlay];
                    playPlayer.playedCards.push(myThis.curMahjong);

                    // 没有给其他玩家发送提示
                    myThis.sendPlayCardPlayer(0, true);
                }
            }
        }else {
            // 之前出的牌没有人操作 ，加入已出过牌中
            player.clearTips();
            var playPlayer = myThis.players[myThis.curPlay];
            playPlayer.playedCards.push(myThis.curMahjong);
            this.sendPlayCardPlayer(0, true);
        }
    },

    onPlayerReqContinue: function(uid) {
        var playerIndex = this.getPlayerIndex(uid);
        if(1 > playerIndex || playerIndex > this.joinedPlayers){
            ERROR(util.format("CONTNUE:    Not player %d's index erorr"));
            return;
        }

        var player = this.players[playerIndex];

        this.players[playerIndex].onPlayerResped();
        if (!player.getReady()) {
            player.setReady(true);

            this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_READY, {
                playerIndex : playerIndex,
            });

            this.readyPlayers += 1;
            if (this.readyPlayers == this.joinedPlayers) {

                this.enumPlayers(function (ePlayerIdx, ePlayer) {
                    if(ePlayer.uid) {
                        ePlayer.reset();
                    }
                });

                // 开始下一局游戏
                if (this.huPlayers.length == 1) {
                    // 只有1人胡牌，设置胡牌玩家为庄家
                    this.dealer = this.getPlayerIdx(this.huPlayers[0]);
                } else if(this.dianPaoUid != 0){
                    // 设置点炮玩家为庄家
                    this.dealer = this.getPlayerIdx(this.dianPaoUid);
                }
                // 所有人就绪
                this.onRoomStartNewRound();
            }
        }
    },

    onPlayerDestroyRoom: function(uid) {
        DEBUG(util.format("Player %d destroy room", uid));
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex == 0) {
            // 该玩家不在这个房间
            return;
        }
        var player = this.getPlayerHandles(uid);
        // 房主解散房间
        if (player && player.uid == this.creator) {
            // 没有发牌才能马上解散 ，发牌以后只有申请解散
            if (!this.hasSendCards) {
                this.destroyRoomImmd();
            }
        }
    },

    onPlayerReqDestroyRoom: function(uid) {
        DEBUG(util.format("Player %d req destroy room", uid));
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex == 0) {
            // 该玩家不在这个房间
            return;
        }
        var player = this.getPlayerHandles(uid);
        if (!this.isReqDestroy && player) {
            // 设置销毁人数
            this.repDestroyPlayerIdx = playerIndex;

            if ((uid == this.creator) && (!this.hasSendCards)) {
                // 房主申请解散并且还没有发牌，直接解散
                this.destroyRoomImmd();
                return;
            } else if (!this.hasSendCards) {
                // 还没发牌
                this.removePlayer(playerIndex);
                return;
            }

            if (this.isSendSett) {
                this.hangupStart = true;
            }

            this.isReqDestroy = true;
            this.destroyTime = Enum.ROOM_DESTROY_TIME + Date.getStamp();
            this.destroyTimer = setTimeout(function(){
                this.curRound = this.totalRound;
                this.onSettement(false);
            }.bind(this), Enum.ROOM_DESTROY_TIME * 1000);

            // 该玩家同意解散
            this.respDestroyOKs[playerIndex] = 1;

            // 广播通知
            this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_REQ_DROOM, {
                name:player.info.name,
                playerIndex : playerIndex,
                destroyTime : this.destroyTime,
            });
        }
    },

    removePlayer: function(playerIndex) {
        var player = this.players[playerIndex];

        this.joinedPlayers -= 1;
        this.onlinePlayers -= 1;


        // 这个玩家滚蛋
        player.sendMsg(Opcodes.SMSG_SET_ROOM_FINISHED, {});
        player.exit();


        // 通知其他人这个SB滚蛋了
        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_EXIT_ROOM, {
            playerIndex : playerIndex,
        });
    },

    onPlayerRespDestroyRoom: function(uid, ok) {
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex == 0) {
            // 该玩家不在这个房间
            return;
        }

        if (ok) {
            if (this.respDestroyOKs.hasOwnProperty(playerIndex)) {
                DEBUG("Player already OK");
                return;
            }
            var player = this.getPlayerHandles(uid);

            // 广播消息
            this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_RESP_DROOM, {
                playerIndex : playerIndex,
                ok          : ok,
                name        : player.info.name,
            });

            this.respDestroyOKs[playerIndex] = 1;
            var okNum = Object.keys(this.respDestroyOKs).length;
            DEBUG(util.format("okNum: %d, destroyPlayers: %d, onlinePlayers: %d"
                , okNum, this.repDestroyPlayerIdx, this.onlinePlayers));
            if (okNum >= this.onlinePlayers) {
                DEBUG("解散房间");

                // 立即解散房间
                clearTimeout(this.destroyTimer);
                this.destroyTimer = null;
                this.isReqDestroy = false;
                this.destroyTime = 0;
                this.respDestroyOKs = {};
                this.repDestroyPlayerIdx = 0;

                if (this.hasSendCards) {
                    this.curRound = this.totalRound;
                    this.onSettement(false);
                } else {
                    this.destroyRoomImmd();
                }
                return;
            }
        } else {
            if (this.respDestroyOKs.hasOwnProperty(playerIndex)) {
                DEBUG("Player already OK");
                return;
            }

            DEBUG("有人不同意");
            var player = this.getPlayerHandles(uid);

            // 广播消息
            this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_RESP_DROOM, {
                playerIndex : playerIndex,
                ok          : ok,
                name:       player.info.name,
            });

            // 该玩家不同意
            if (this.destroyTimer) {
                clearTimeout(this.destroyTimer);
                this.destroyTimer = null;
                this.isReqDestroy = false;
                this.destroyTime = 0;
                this.respDestroyOKs = {};
                this.repDestroyPlayerIdx = 0;
            }

            if (this.hangupStart) {
                this.onRoomStartNewRound();
            }
        }
    },

    // 广播用户消息
    onPlayerReqBroadcastMessage: function(uid, message, msgId, sex) {
        var playerIndex = this.getPlayerIndex(uid);
        this.broadcastMsg(Opcodes.SMSG_BROADCAST_MESSAGE, {
            playerIndex : playerIndex,
            message     : message,
            msgId       : msgId,
            sex         : sex,
        }, [playerIndex]);
    },


    onPlayerReqExitRoom: function(uid) {
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex == 0) {
            // 该玩家不在这个房间
            return;
        }
        var player = this.players[playerIndex];

        if(player.uid == this.creator){
            // 房主不能退出房间，只有解散房间
            return;
        }
        if (this.hasSendCards) {
            // 已经发牌，不能退出了
            return;
        }
        this.joinedPlayers -= 1;
        this.onlinePlayers -= 1;
        this.readyPlayers -= 1;

        // 房主退出 ，房间解散
        if (player.uid == this.creator) {
            this.destroyRoomImmd();
            return;
        }else{
            GameMgr.sendMgrMsg({
                code    : ProtoID.SMSG_PLAYER_THIS_EXIT_ROOM,
                args    : {
                    uid : player.uid,
                },
            });
        }
        player.destroy();

        this.broadcastMsg(Opcodes.SMSG_SET_PLAYER_EXIT_ROOM, {
            playerIndex : playerIndex,
        });
    },
    onPlayerInRoomReady: function(uid) {
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex == 0) {
            // 该玩家不在这个房间
            return;
        }
        var player = this.players[playerIndex];
        // 已经准备
        if(player.getReady()){
            return;
        }
        this.readyPlayers += 1;

        // 响应玩家准备成功
        player.setReady(true);
        player.sendMsg(Opcodes.SMSG_PLAYER_ROOM_READY_OK, {isReady: true});

        // 开始游戏
        if (this.readyPlayers == Enum.ROOM_PLAYER_NUM && this.readyPlayers == this.joinedPlayers) {
            // 已经发牌，  不能退出房间
            this.hasSendCards = true;

            // 设置庄家
            this.dealer = this.getPlayerIdx(this.creator);

            // 扣除房主房卡
            var card = this.totalRound == 16 ? 2 : 1;
            GameMgr.decPlayerCard(this.creator, this.id, card);

            this.onRoomStartNewRound();
        }

    },

    onRoomGetPlayerCard: function(uid, card) {
        var playerIndex = this.getPlayerIndex(uid);
        if (playerIndex == 0 || !card) {
            // 该玩家不在这个房间
            return;
        }
        var player = this.players[playerIndex];
        // 获取到指定玩家的房卡信息，发送给玩家
        player.sendMsg(ProtoID.SMSG_SEND_PLAYER_CARD_CHANGE, {card : card,});
    },

    getHuPaiTypeBaseScore: function(player) {
        // 创建房间时分的鱼
        var integral = 0;
        // 底分
        var baseScore = 0;
        // 翻数
        var Multiple = 1;
        // 平胡2分， 自摸3分
        if(player.hasHuPaiMethod(Enum.HupaiMethod.METHOD_ZIMO_PAIRS)) {
            baseScore = 3;
        }else{
            baseScore = 2;
        }

        if (player.hasHuPaiType(Enum.HupaiType.METHOD_13_PAIRS)) {
            if(player.isWindAll){
                Multiple += 1;
            }
            integral += baseScore * Multiple;
        } else if (player.hasHuPaiType(Enum.HupaiType.METHOD_7_PAIRS)) {
            Multiple += 1;
            integral += baseScore * Multiple;
        } else if (player.hasHuPaiType(Enum.HupaiType.METHOD_GK_PAIRS)){
            Multiple += 1;
            integral += baseScore * Multiple;
        }else if (player.hasHuPaiType(Enum.HupaiType.METHOD_PINHUI_PAIRS)) {
            integral += baseScore * Multiple;
        }
        player.sethuPaiMultiple(Multiple);

        return integral;
    },

    decPlayerIntegral: function(what, num, excludes) {
        excludes = excludes || [];
        this.enumPlayers(function(ePlayerIdx, ePlayer){
            if (excludes.indexOf(ePlayer.uid) != -1) {
                return;
            }
            ePlayer.decIntegral(what, num);
            ePlayer.decHuPaiScore(num);
        });
    },
    decPlayerIntegralWhoHasHuiPaiMethod: function(num, method) {
        this.enumPlayers(function(ePlayerIdx, ePlayer){
            if (!ePlayer.isHu() && ePlayer.hasHuPaiMethod(Enum.HupaiMethod.METHOD_COVER_DIANPAO) && (ePlayer.uid == this.dianPaoUid)) {
                ePlayer.decIntegral(method, num);
                ePlayer.decHuPaiScore(num);
                return false;
            }
        }.bind(this));
    },

    /**
     *  结算杠牌
     */
    zuoJiang258SettlementGangCardAction: function () {
        var room = this;
        if(!room) {
            return ;
        }
        for (var key in room.players) {
            if (!room.players.hasOwnProperty(key)) {
                continue;
            }
            var curPlay = room.players[key];
            var cunDianGangCards = [];
            var integral = 0;

            //玩家听牌， 并且没有热炮
            var curGangDate = curPlay.handsCards.getSynGangCardDate();
            //听牌条件下，检查自己的鸡和豆并结算积分
            curGangDate.forEach(function (gangs) {
                switch (gangs.mark) {
                    case Enum.PlayerMark.PLAYER_TIP_AG://暗杠
                        integral = (room.joinedPlayers - 1) * 2;
                        curPlay.incIntegral(gangs.mark, integral);
                        curPlay.anGangNum += 1;
                        break;
                    case Enum.PlayerMark.PLAYER_TIP_MG://明杠
                    case Enum.PlayerMark.PLAYER_TIP_JG://加杠
                        integral = 1;
                        curPlay.incIntegral(gangs.mark, integral);
                        curPlay.mingGangNum += 1;
                        break;
                    case Enum.PlayerMark.PLAYER_TIP_BG: // 被明杠
                        //别的玩家身上判断是否听牌后再做处理
                        cunDianGangCards.push(gangs);
                        break;
                    default:
                        break;
                }
            });

            for (var pos in room.players) {
                if(!room.players.hasOwnProperty(pos)){
                    continue;
                }
                var play = room.players[pos];
                //检查其它玩家鸡和豆并当前玩家的扣积分，未听牌时鸡和豆不计分，跳过
                if (curPlay == play) {
                    continue;
                }
                var otherGangDate = play.handsCards.getSynGangCardDate();
                //听牌条件下，检查自己的鸡和豆并结算积分
                otherGangDate.forEach(function (gangs) {
                    switch (gangs.mark) {
                        case Enum.PlayerMark.PLAYER_TIP_AG://暗杠
                            integral = 2;
                            curPlay.decIntegral(gangs.mark, integral);
                            break;
                        case Enum.PlayerMark.PLAYER_TIP_JG://加杠
                            integral = 1;
                            curPlay.decIntegral(gangs.mark, integral);
                            break;
                        case Enum.PlayerMark.PLAYER_TIP_MG://明杠
                            //其它玩家点杠了当前玩家的牌
                            cunDianGangCards.forEach(function (card) {
                                if (card.mark == Enum.PlayerMark.PLAYER_TIP_BG && card.value == gangs.value) {
                                    integral = 1;
                                    curPlay.decIntegral(gangs.mark, integral);
                                }
                            });
                            break;
                            break;
                        case Enum.PlayerMark.PLAYER_TIP_BG: // 被明杠
                            //mjMark.PLAY_MARK_APPOINT_GANG已经处理了
                            break;
                        default:
                            break;
                    }
                });
            }
        }
    },

    // 带混给杠加计数
    daiHunSettlementGangCardAction :function () {
        this.enumPlayers(function (ePlayerIdx, ePlayer) {
            if(ePlayer.uid != 0){
                //玩家听牌， 并且没有热炮
                var curGangDate = ePlayer.handsCards.getSynGangCardDate();
                //听牌条件下，检查自己的鸡和豆并结算积分
                curGangDate.forEach(function (gangs) {
                    switch (gangs.mark) {
                        case Enum.PlayerMark.PLAYER_TIP_AG://暗杠
                            ePlayer.anGangNum += 1;
                            break;
                        case Enum.PlayerMark.PLAYER_TIP_MG://明杠
                        case Enum.PlayerMark.PLAYER_TIP_JG://加杠
                            ePlayer.mingGangNum += 1;
                            break;
                        case Enum.PlayerMark.PLAYER_TIP_BG: // 被明杠
                            //别的玩家身上判断是否听牌后再做处理
                            break;
                        default:
                            break;
                    }
                });
            }
        });
    },

    onDaiHunSettement : function () {
        // 计算胡牌方式
        var myThis = this;
        var integral = 0;
        for (var playerIdx in myThis.players) {
            if (!myThis.players.hasOwnProperty(playerIdx)) {
                continue;
            }
            var ePlayer = myThis.players[playerIdx];
            if (!ePlayer.isHu()) {
                continue;
            }
            // 胡牌愁番数
            var playerBaseScore = this.getHuPaiTypeBaseScore(ePlayer);
            var gangNum = 0;
            // 几杠算几番
            for(var pos in ePlayer.handsCards.GANGs){
                if(!ePlayer.handsCards.GANGs.hasOwnProperty(pos)){
                    continue;
                }
                // 被杠跳过
                var iGang = ePlayer.handsCards.GANGs[pos];
                if(iGang.mark == Enum.PlayerMark.PLAYER_TIP_BG) {
                    continue;
                }
                playerBaseScore *= 2;
                ++gangNum;
                ePlayer.sethuPaiMultiple(1);
            }
            // 带根数量
            var beltRootNum = ePlayer.handsCards.getHasBeltRootNum();;
            for(var pos = 0; pos < beltRootNum;pos++){
                playerBaseScore *= 2;
                ++gangNum;
            }
            // 番数加上底分鱼
            playerBaseScore += myThis.roomIntegral + gangNum;

            if (ePlayer.hasHuPaiMethod(Enum.HupaiMethod.METHOD_ZIMO_PAIRS)) {
                // 玩家自摸

                integral += playerBaseScore * (this.joinedPlayers - 1);

                // 给玩家加分
                ePlayer.incIntegral(Enum.HupaiMethod.METHOD_ZIMO_PAIRS, integral);
                ePlayer.incHuPaiScore(integral);

                // 扣除其他玩家积分
                this.decPlayerIntegral(Enum.HupaiMethod.METHOD_ZIMO_PAIRS, playerBaseScore, [ePlayer.uid]);
                break;
            }
            if (ePlayer.hasHuPaiMethod(Enum.HupaiMethod.METHOD_DIANPAO_PAIRS)) {
                // 点炮

                ePlayer.incIntegral(Enum.HupaiMethod.METHOD_DIANPAO_PAIRS, playerBaseScore);
                ePlayer.incHuPaiScore(playerBaseScore);

                // 扣除点炮玩家积分
                this.decPlayerIntegralWhoHasHuiPaiMethod(playerBaseScore);
                continue;
            }
        }
        // 带混给杠加计数
        //this.daiHunSettlementGangCardAction();

    },
    onZuoJiangSettement : function () {
        // 计算胡牌方式
        var myThis = this;
        var integral = 0;
        for (var playerIdx in myThis.players) {
            if (!myThis.players.hasOwnProperty(playerIdx)) {
                continue;
            }
            var ePlayer = myThis.players[playerIdx];
            if (!ePlayer.isHu()) {
                continue;
            }
            // 胡牌的番数
            var playerBaseScore = this.getHuPaiTypeBaseScore(ePlayer);
            var gangNum = 0;
            // 几杠算几番
            for(var pos in ePlayer.handsCards.GANGs){
                if(!ePlayer.handsCards.GANGs.hasOwnProperty(pos)){
                    continue;
                }
                var iGang = ePlayer.handsCards.GANGs[pos];
                // 被杠跳过
                if(iGang.mark == Enum.PlayerMark.PLAYER_TIP_BG) {
                    continue;
                }
                playerBaseScore *= 2;
                ++gangNum;
                ePlayer.sethuPaiMultiple(1);
            }
            // 带根数量
            var beltRootNum = ePlayer.handsCards.getHasBeltRootNum();;
            for(var pos = 0; pos < beltRootNum;pos++){
                playerBaseScore *= 2;
                ++gangNum;
            }
            // 番数加上底分鱼
            playerBaseScore += myThis.roomIntegral + gangNum;

            if (ePlayer.hasHuPaiMethod(Enum.HupaiMethod.METHOD_ZIMO_PAIRS)) {
                // 玩家自摸

                integral += playerBaseScore * (this.joinedPlayers - 1);

                // 给玩家加分
                ePlayer.incIntegral(Enum.HupaiMethod.METHOD_ZIMO_PAIRS, integral);
                ePlayer.incHuPaiScore(integral);

                // 扣除其他玩家积分
                this.decPlayerIntegral(Enum.HupaiMethod.METHOD_ZIMO_PAIRS, playerBaseScore, [ePlayer.uid]);
                break;
            }
            if (ePlayer.hasHuPaiMethod(Enum.HupaiMethod.METHOD_DIANPAO_PAIRS)) {
                // 点炮

                ePlayer.incIntegral(Enum.HupaiMethod.METHOD_DIANPAO_PAIRS, playerBaseScore);
                ePlayer.incHuPaiScore(playerBaseScore);

                // 扣除点炮玩家积分
                this.decPlayerIntegralWhoHasHuiPaiMethod(playerBaseScore);
                continue;
            }
        }
        // 结算杠牌
        //this.zuoJiang258SettlementGangCardAction();
    },
    // 结算
    onSettement: function(isNormal) {
        DEBUG("Room::onSettement");
        var myThis = this;
        myThis.hangupStart = true;

        // 设置就绪状态 和检查听牌
        myThis.readyPlayers = 0;
        // 是否正常结算
        //if(isNormal) {
            myThis.enumPlayers(function (eNotUse, ePlayer) {
                ePlayer.setReady(false);
                ePlayer.checkTingPai();
            });
            if (myThis.isHupai) {
                // 检查玩家听牌
                if (1 == myThis.roomType) {
                    myThis.onDaiHunSettement();
                } else if (2 == myThis.roomType) {
                    myThis.onZuoJiangSettement();
                }
            } else {
                // 流局，什么都不管还是上家庄家
            }
        //}
        // 发送结算信息
        var settementInfo = {};

        settementInfo["round"] = myThis.curRound;
        settementInfo["wind"] = myThis.selectWind;
        settementInfo["yuNum"] = myThis.roomIntegral;
        settementInfo["players"] = null;
        var playerinfo = [];
        var playBattle = {};
        for (var playerIdx in myThis.players) {
            if (!myThis.players.hasOwnProperty(playerIdx)) {
                continue;
            }
            var ePlayer = myThis.players[playerIdx];
            if(!ePlayer.uid){
                continue;
            }
            playerinfo.push(ePlayer.getSettementInfo());

            /*///////////////////// save playback date
            playBattle[playerIdx] = {
                name: ePlayer.info.name,
                score: ePlayer.roundScore,
            };
            myThis.roomPlayInfoPage[playerIdx].score = ePlayer.score;
            ////////////////////////////////////////*/
        }

        /*///////////////////// save playback date
        myThis.playBackDates.push({
            curRound: myThis.curRound,
            roomId: myThis.id,
            roomType: myThis.roomType,
            time: Date.getStamp(),
            playBattle: playBattle,
            operation: myThis.playBackPage,
            roomInfo: myThis.roomPlayInfoPage,
        });
        myThis.playBackPage = [];
        ////////////////////////////////////////*/

        settementInfo["players"] = playerinfo;
        // 广播结算信息
        myThis.broadcastMsg(Opcodes.SMSG_SET_ROUND_SETTEMENT, settementInfo);

        if ((myThis.curRound >= myThis.totalRound)) {
            // 总结算
            myThis.onGameOver();
        }
    },

    // 游戏结束
    onGameOver: function() {
        DEBUG("==== GAME OVER");
        var myThis = this;

        // 至少打完一局才保存战绩
        var room = this;
        var AllPlayersInfo = [];
        myThis.enumPlayers(function (ePlayerIdx, ePlayer) {
            if (ePlayer.uid != 0) {
                AllPlayersInfo.push({
                    name: ePlayer.info.name,
                    id: ePlayer.uid,
                    headpic: ePlayer.info.headpic,
                    isOwner: ePlayer.uid == room.creator,
                    ziMoCount: ePlayer.ziMoNum,
                    jiePaoCount: ePlayer.jiePaoNum,
                    dianpaoCount: ePlayer.dianPaoNum,
                    angangCount: ePlayer.anGangNum,
                    minggangCount: ePlayer.mingGangNum,
                    score: ePlayer.score,
                });
            }
        });

        // 总结算
        myThis.broadcastMsg(Opcodes.SMSG_SET_FROUND_SETTEMENT, {players:AllPlayersInfo});

        if(this.curRound > 1) {
            // 保存战绩
            var playerReports = {};
            var uids = [];
            playerReports["roomID"] = this.id;
            playerReports["time"] = Date.getStamp();

            var reports = [];
            myThis.enumPlayers(function (ePlayerIndex, ePlayer) {
                uids.push(ePlayer.uid);
                reports.push({
                    uid: ePlayer.uid,
                    name: ePlayer.info.name,
                    score: ePlayer.score,
                });
            });

            playerReports["player"] = reports;

            GameMgr.sendMgrMsg({
                code: ProtoID.SMSG_REQ_SAVE_REPORTS,
                args: {
                    uids: uids,
                    players: {
                        reportsDate:playerReports,
                        /*///////////////////// save playback date
                        playBackDate:myThis.playBackDates,
                        /////////////////////////////////////////*/
                    },
                },
            });
        }

        // 销毁房间
        setTimeout(function () {
            DEBUG(util.format("==== Destroy Room %d"), myThis.id);
            myThis.onRoomDestroy();
        }, 2000);

        // 减少房间用量
        GameMgr.decUsage();
        GameMgr.getSubGame().destroyRoom(this);
    },
};

exports.Room = Room;

/*var card = null
 if(ePlayerIndex == 1){
 card = [
 {"type":1,"value":1}, {"type":1,"value":1}, {"type":1,"value":1},
 {"type":1,"value":1},   {"type":1,"value":2},   {"type":1,"value":2},
 {"type":1,"value":3},   {"type":1,"value":3},   {"type":1,"value":3},   {"type":1,"value":3},
 {"type":1,"value":4},   {"type":1,"value":4},   {"type":1,"value":4},
 ];    }else if(ePlayerIndex == 2){
 card = [
 {"type":1,"value":1},
 {"type":1,"value":2},
 {"type":1,"value":4},
 {"type":1,"value":5},   {"type":1,"value":5},   {"type":1,"value":5},   {"type":1,"value":5},
 {"type":1,"value":6},   {"type":1,"value":6},   {"type":1,"value":6},   {"type":1,"value":6},
 {"type":2,"value":6},   {"type":2,"value":6},
 ];  }else if(ePlayerIndex == 3){
 card = [
 {"type":1,"value":7}, {"type":1,"value":7},
 {"type":1,"value":8},   {"type":1,"value":8},   {"type":1,"value":8},   {"type":1,"value":10},
 {"type":1,"value":9},   {"type":1,"value":9},   {"type":1,"value":9},   {"type":1,"value":9},
 {"type":2,"value":1},   {"type":2,"value":1},   {"type":2,"value":1},
 ];    }else{
 card = [
 {"type":2,"value":1},
 {"type":2,"value":2},{"type":2,"value":2},{"type":2,"value":2},{"type":2,"value":2},
 {"type":2,"value":3},{"type":2,"value":3},{"type":2,"value":3},{"type":2,"value":3},
 {"type":2,"value":4},{"type":2,"value":4},{"type":2,"value":4},{"type":2,"value":4},
 ];          }
 ePlayer.setHandCards(card);*/
